using System.Collections.Generic;
using OhioState.Graphics;
using OhioState.Graphics.Proxy;
using OhioState.Math;
using Tao.OpenGl;



namespace OhioState.Graphics.OpenGL
{

    public class ROIBoxGL : IDrawable
    {
        //private OhioState.Graphics.ROIBox _roiBoxProxy;
        private float _sliceThickness;
        public float SliceThickness
        {
            get { return _sliceThickness; }
            set { _sliceThickness = value; }
        }
        private Vector3 _sliceDirection;
        public Vector3 SliceDirection
        {
            get { return _sliceDirection; }
            set { _sliceDirection = value; }
        }
        private Matrix4 _worldToROI;
        public Matrix4 WorlToROIMatrix
        {
            get { return _worldToROI; }
            set { _worldToROI = value; }

        }
        private Matrix4 _roiToTexture;
        public Matrix4 ROIToTextureMatrix
        {
            get { return _roiToTexture; }
            set { _roiToTexture = value; }
        }
        #region IDrawable Properties
        private IMaterial _material;
        public IMaterial Material
        {
            get { return _material; }
            set { _material = value; }
        }
        private BoundingBox _box;
        public IBoundingVolume BoundingVolume
        {
            get { return _box; }
        }
        private int _drawablePosition;
        public int DrawablePosition
        {
            get { return _drawablePosition; }
            set { _drawablePosition = value; }
        }
       
        #endregion IDrawable Properties

        private BoxSlicer _slicer;
        public ROIBoxGL(BoundingBox box)
        {
            _box = new BoundingBox(box);
            _slicer = new BoxSlicer(_box);
        }

        #region GL Methods
        //
        // Render the ROI
        //
        public void Render(IRenderPanel panel)
        {
           
            //
            // Set the material.
            //
            if (_material != null)
            {
                _material.MakeActive(panel);
            }

            Gl.glDisable(Gl.GL_CULL_FACE);
            //
            // begin slicing the ROI
            //

            BeginSlicing();

            //Gl.glBegin(Gl.GL_QUADS);
            //Gl.glColor3f(1.0f, 0.0f, 0.0f);
            //Gl.glVertex3f(0.0f, 0.0f, 0.0f);
            //Gl.glColor3f(1.0f, 0.0f, 0.0f);
            //Gl.glVertex3f(0.0f, 0.0f, 1.0f);
            //Gl.glVertex3f(1.0f, 1.0f, 1.0f);
            //Gl.glColor3f(1.0f, 0.0f, 0.0f);
            //Gl.glVertex3f(1.0f, 1.0f, 0.0f);
            //Gl.glEnd();
            //
            // render each slice
            //
            bool doneSlicing = false;
            while (!doneSlicing)
            {
                //
                // get the next slice
                //
                doneSlicing = !_slicer.AdvanceSlice(_sliceThickness);
                //
                // render the slice
                //
                RenderSlice();
            }
            //
            // end slicing
            //
            EndSlicing();
            //
            // Deactivate the material
            //
            if (_material != null)
            {
                _material.Deactivate(panel);
            }
        }
        //
        // iterator methods, called from volume shader to iterate all slices within the ROI
        //
        private void initOpenGLSettings()
        {

            Gl.glFrontFace(Gl.GL_CW);

            Gl.glActiveTexture(Gl.GL_TEXTURE0);
            Gl.glMatrixMode(Gl.GL_TEXTURE);
            Gl.glPushMatrix();
            float[] roi2tex;
            _roiToTexture.GetValue(out roi2tex);
            Gl.glLoadMatrixf(roi2tex);
            float[] wld2roi;
            _worldToROI.GetValue(out wld2roi);
            Gl.glMultMatrixf(wld2roi);

           
            //
            // Set the model view matrix for slicing
            //
            //Gl.glMatrixMode(Gl.GL_MODELVIEW);
            //Gl.glPushMatrix();
            //float[] roi2wld;
            //_roiBoxProxy.GetRoiToWorldMatrix().getValue(out roi2wld);
            //Gl.glMultMatrixf(roi2wld);
        }
        private void BeginSlicing()
        {

            //
            //  Set the slice advancing direction in ROI space
            //
            Vector4 temp = new Vector4(0.0f, 0.0f, 0.0f, 1.0f);
            Vector4 p0 = _worldToROI * temp;
            // advance_dir is defined in world space
            Vector3 advance_dir = _sliceDirection;
            temp = new Vector4(advance_dir[0], advance_dir[1], advance_dir[2], 1.0f);
            Vector4 p1 = _worldToROI * temp;
            temp = p1 - p0;
            Vector3 temp2 = new Vector3(temp[0], temp[1], temp[2]);
            temp2.normalize();
            _slicer.BeginSlicing(temp2);
            initOpenGLSettings();
        }

        private void EndSlicing()
        {
            //
            // Set back the model view matrix
            //
            Gl.glActiveTexture(Gl.GL_TEXTURE0);
            Gl.glMatrixMode(Gl.GL_TEXTURE);
            Gl.glPopMatrix();
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            //Gl.glPopMatrix();
        }

        //
        // Render each slice in ROI
        //
        private void RenderSlice()
        {
            Gl.glBegin(Gl.GL_TRIANGLE_FAN);
            List<Vector3> slice = _slicer.CurrentSlice;
            foreach( Vector3 vert in slice)
            {
                //
                // Set the texture coordinates?
                //
                Gl.glTexCoord3fv(vert.getValue());
                Gl.glVertex3fv(vert.getValue());
            }
            Gl.glEnd();
        }

        #endregion

    }
}
